package dao

import (
	"errors"
	"gorm.io/gorm"
	"log"
	"time"
	"ztool/common"
	"ztool/dao/type"
	"ztool/models"
)

// VideoDevice 视频点位 此结构体需要在main中更新，否则表结构不能自动更新
type VideoDevice struct {
	ID        _type.SnowflakeId `json:"id" form:"id" gorm:"primaryKey"`       //json指定string 解决前端雪花id精度丢失问题
	LinkId    string            `json:"linkId" form:"linkId" gorm:"index"`    //业务关联ID
	Name      string            `json:"name" form:"name"`                     //名称
	Type      int8              `json:"type" form:"type"`                     //0 stream  1 GB28181
	Longitude _type.StrFloat64  `json:"longitude,omitempty" form:"longitude"` //经度
	Latitude  _type.StrFloat64  `json:"latitude,omitempty" form:"latitude"`   //维度
	Stream    string            `json:"stream" form:"stream"`                 //流地址
	Remark    string            `json:"remark" form:"remark"`                 //备注
	CreatedAt time.Time         `json:"created_at"`                           //创建时间
	Tags      *[]Tag            `gorm:"-" json:"tags,omitempty" form:"tags"`  //对应标签
}

// VideoTags 点位标签关联表
type VideoTags struct {
	ID      int64             `json:"id"`
	VideoId _type.SnowflakeId `json:"video_id"`
	TagId   _type.SnowflakeId `json:"tag_id"`
}

// AddVideoDevice 添加点位
func AddVideoDevice(device *VideoDevice) error {
	//获取db对象
	db := common.GetDB()

	//开启事务
	db.Transaction(func(tx *gorm.DB) error {
		//1.插入设备
		//雪花ID
		device.ID = _type.GenerateSnowflakeId()
		//创建
		if err := tx.Model(&VideoDevice{}).Create(device).Error; err != nil {
			return err
		}

		//判断标签长度
		if len(*device.Tags) > 0 {
			log.Printf("标签共 %d 个", len(*device.Tags))
			//2.处理标签
			if err := AddTags(device.Tags, tx); err != nil {
				return err
			}

			//3.插入中间表
			if err := AddVideoTags(device, tx); err != nil {
				//回滚
				log.Printf("发生错误,准备回滚, %s", err.Error())
				return err
			}
		}

		return nil
	})

	return nil
}

// AddVideoTags 批量添加
func AddVideoTags(device *VideoDevice, tx *gorm.DB) error {
	log.Println("批量插入设备标签关联表")

	//创建切片
	var addTags []*VideoTags

	tags := device.Tags

	for i := 0; i < len(*tags); i++ {
		tag := (*tags)[i]

		if tag.ID.SnowflakeIdIsEmpty() {
			//tagID为空,报错,让程序回滚
			return errors.New("获取标签ID失败")
		}

		videoTag := VideoTags{
			VideoId: device.ID,
			TagId:   tag.ID,
		}

		addTags = append(addTags, &videoTag)
	}

	if len(addTags) > 0 {
		log.Printf("关联标签 %d 个", len(*device.Tags))
		//批量插入
		return tx.Create(&addTags).Error
	}

	return nil
}

// UpdateVideoDevice 编辑点位
func UpdateVideoDevice(device *VideoDevice) error {
	db := common.GetDB()

	//开启事务
	db.Transaction(func(tx *gorm.DB) error {
		//1.插入设备
		//更新
		if err := tx.Model(&device).Omit("create_at", "id").Updates(device).Error; err != nil {
			return err
		}

		//2.删除所有标签关联
		if err := tx.Where("video_id = ?", device.ID).Delete(&VideoTags{}).Error; err != nil {
			return err
		}

		//3.处理标签
		if err := AddTags(device.Tags, tx); err != nil {
			return err
		}

		//3.插入中间表
		if err := AddVideoTags(device, tx); err != nil {
			//回滚
			log.Printf("发生错误,准备回滚, %s", err.Error())
			return err
		}

		return nil
	})

	return nil
}

// QueryVideoDevicePage 分页查询
func QueryVideoDevicePage(page int32, name string, tags []string) *models.Pages {
	db := common.GetDB()

	//转换页码
	page = page - 1

	//查询总数
	var rows int64
	db.Model(&VideoDevice{}).Count(&rows)

	result := models.Pages{}

	//查询分页
	var videos []VideoDevice

	d := db.Model(&VideoDevice{})

	if len(tags) > 0 {
		//查询出所有相关标签
		var deviceIds []string
		//查询所有符合的标签，并且查询结果>=标签的数量，因为每个设备的标签是唯一的
		db.Raw("select video_id from video_tags where tag_id in ? "+
			"group by video_id having count(video_id) >= ?", tags, len(tags)).Scan(&deviceIds)
		d = d.Where("id in ?", deviceIds)
	}

	if len(name) > 0 {
		//有名称
		d = d.Where("name like ? ", "%"+name+"%")
	}

	d.Limit(int(common.PAGE_OFFSET)).Offset(int(common.PAGE_OFFSET * page)).Find(&videos)

	result.Total = rows
	result.PageOffset = common.PAGE_OFFSET
	result.Current = page
	result.Data = &videos

	return &result
}

// QueryAllVideoDevice 查询所有
func QueryAllVideoDevice() (*[]VideoDevice, error) {
	db := common.GetDB()

	//查询所有
	var videos []VideoDevice
	error := db.Model(&VideoDevice{}).Find(&videos).Error

	return &videos, error
}

// DeleteVideoDevice 删除
func DeleteVideoDevice(id string) error {
	db := common.GetDB()

	db.Transaction(func(tx *gorm.DB) error {
		//1.删除设备
		if err := tx.Delete(&VideoDevice{}, id).Error; err != nil {
			return err
		}

		//2.删除关系表
		if err := tx.Where("video_id = ?", id).Delete(&VideoTags{}).Error; err != nil {
			return err
		}

		return nil
	})

	return nil
}

// QueryVideoTags 查询设备关联的标签
func QueryVideoTags(videoId string) (*[]Tag, error) {
	db := common.GetDB()

	var tags []Tag

	err := db.Raw("select t.id, t.content, t.created_at from video_tags as vt "+
		"left join tags as t on vt.tag_id = t.id "+
		"where vt.video_id = ?", videoId).Scan(&tags).Error

	return &tags, err
}
